# coding:utf-8
# 根据漫画json文件下载作品图片和创建HTML文件

import json
from urllib import request
import os
import re
import socket
from threading import Thread
import requests


class DownloadOfThread():
    '''
    多线程下载文件类
    '''
    # 基础变量设置

    HEADERS = ("User-Agent",
               "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0")  # header头

    def __init__(self, json_file_name: str, saveDir: str, threadNum: int = 4, timeOut: int = 60, headers: list = [HEADERS]):
        # 设置超时时间
        socket.setdefaulttimeout(timeOut)
        # 设置header头，防止被抓
        opener = request.build_opener()
        opener.addheaders = headers

        self.json_file_name = json_file_name
        self.threadNum = threadNum
        self.saveDir = saveDir

    def Start(self):
        if not os.path.exists(self.json_file_name):
            print(self.json_file_name+'不存在')
            return None
        # 判断有无下载失败文件,有就删除
        # failedFileName = os.path.splitext(self.json_file_name)[0]+'_下载失败.json'
        # if os.path.exists(failedFileName):
        #     failedNameList = self.GetJsonData(failedFileName)
        #     for i in failedNameList:  # type:set
        #         if os.path.exists(i["fileName"]):
        #             os.remove(i["fileName"])
        #             print(i["fileName"]+'已删除，准备重新下载')

        jsonData = self.GetJsonData(self.json_file_name)
        jsonList = self.ListSplit(jsonData, self.threadNum)
        threadList = []  # 线程数组
        threadid = 1
        for i in jsonList:
            threadList.append(DownloadFile(i, self.saveDir,threadid))
            threadid+=1
        for i in threadList:
            i.start()
        for i in threadList:
            i.join()
        # failedList = []
        # for i in threadList:
        #     failedList += i.GetFailedList()
        # self.SaveListToJsonFile(failedList, failedFileName)

    def SaveListToJsonFile(self, list1, fileName):
        f = open(fileName, 'w', encoding="utf-8")
        text = json.dumps(list1, sort_keys=True,
                          indent=4, ensure_ascii=False)
        f.write(text)
        f.close()

    def ListSplit(self, srcList: list, num: int) -> list:
        '''
        把一个数组切割成几个数组
        '''
        srcListLen = srcList.__len__()
        # num不能少于1
        if num < 1:
            num = 1
        # 判断数组长度是否大于线程数
        if srcListLen >= num:
            splitList = []
            listLen = int(srcListLen/num)  # 单个数组长度
            for i in range(num-1):
                splitList.append(srcList[i*listLen:(i+1)*listLen])
            splitList.append(srcList[(num-1)*listLen:srcListLen])
            return splitList
        else:
            splitList = []
            for i in srcList:
                splitList.append(i)
            return splitList

    def GetJsonData(self, fileName: str) -> list:
        f = open(fileName, 'r', encoding="utf-8")
        text = f.read()
        f.close()
        dataList = json.loads(text)
        return dataList


class DownloadFile(Thread):
    '''
    下载线程，可以重写run函数
    '''

    def __init__(self, json1, saveDir:str,threadid:int):
        super().__init__()
        self.json = json1
        self.savaDir = saveDir
        self.threadid=threadid
        self.downedNum=0    # 已经下载的照片数量
        self.downNum=self.GetDownNum()  # 需要下载的照片数量
        self.failedList = []
        self.session = requests.session()

    def run(self):
        for ji_he in self.json:  # type : set
            section = ji_he['sectionName']
            section = re.sub('[\\/:.*?"<>|]', '', section)  # 过滤非法字符
            section_path = self.savaDir+'/'+section
            if not os.path.exists(section_path):
                os.makedirs(section_path)
            n = 0  # 图片序号
            pictureUrls = ji_he['picturesUrls']
            for picture_url in pictureUrls:
                if n < 10:
                    file_name = section_path+'/' + \
                        str(ji_he['imgPage'])+'_00'+str(n)+'.jpg'
                elif n < 100:
                    file_name = section_path+'/' + \
                        str(ji_he['imgPage'])+'_0'+str(n)+'.jpg'
                else:
                    file_name = section_path+'/' + \
                        str(ji_he['imgPage'])+'_'+str(n)+'.jpg'

                # 判断有无图片，有就不下载
                if not os.path.exists(file_name):
                    try:
                        # req.urlretrieve(picture_url, file_name)

                        r1 = self.session.get(picture_url, timeout=(10, 30))
                        if r1.status_code == 200:
                            with open(file_name, "wb") as f:
                                f.write(r1.content)
                            print('线程{threadid}:{file_name}下载完成,已下载{downed}/{len1}'.format(threadid=str(self.threadid),file_name=file_name,downed=str(self.downedNum),len1=str(self.downNum)))
                            self.downedNum+=1
                        else:
                            self.failedList.append(
                                {'fileName': file_name, "page": str(ji_he['imgPage']), "n": n, 'url': picture_url})
                            print('线程{threadid}:{file_name}下载失败,已下载{downed}/{len1}'.format(threadid=str(self.threadid),file_name=file_name,downed=str(self.downedNum),len1=str(self.downNum)))
                            print('url:'+picture_url)
                            if os.path.exists(file_name):
                                os.remove(file_name)
                                print(file_name+'已删除，请准备重新下载')

                    except socket.timeout:
                        # self.failedList.append(
                        #     {'fileName': file_name, "page": ji_he['page'], "n": n, 'url': picture_url})
                        # print(file_name+'下载失败')
                        # print('url:'+picture_url)
                        # if os.path.exists(file_name):
                        #     os.remove(file_name)
                        #     print(file_name+'已删除，请准备重新下载')
                        self.session.close()
                    except Exception as e:
                        self.downNum-=1
                        print(e)
                else:
                    self.downNum-=1
                n += 1
        print("线程%d总共已下载%d/%d"%(self.threadid,self.downedNum,self.downNum))
        self.session.close()

    def GetFailedList(self):
        return self.failedList
    
    def GetDownNum(self)->int:
        '''
        获取照片需要下载的长度
        '''
        len1=0
        for ji_he in self.json:
            pictureUrls_len = len(ji_he['picturesUrls'])
            len1+=pictureUrls_len
        return len1


def CreateIndexJson(作品文件夹: str):
    '''
    生成漫画章节索引json
    '''
    if os.path.exists(作品文件夹):
        章节索引 = []
        章节文件夹名s: list = next(os.walk(作品文件夹))[1]

        # 章节名排序

        不能排序章节名 = []  # 最后不能排序的章节名
        dirs_sort = {}
        r1 = re.compile(r'[0-9]*[0-9]')
        for 章节文件夹名 in 章节文件夹名s:
            # dir #type:str
            num = r1.search(章节文件夹名)
            if not (num is None):
                num = int(num.group())
                dirs_sort[num] = 章节文件夹名
            else:
                不能排序章节名.append(章节文件夹名)

        章节文件夹名s = []
        keys = list(dirs_sort.keys())
        keys.sort()
        for i in keys:
            章节文件夹名s.append(dirs_sort[i])
        for i in 不能排序章节名:
            章节文件夹名s.append(i)

        # 把照片排序写入到索引中

        for i in 章节文件夹名s:
            files = os.listdir(作品文件夹+"/"+i)
            files.sort()
            章节索引.append({"dir": i, "pictrue": files})
        projectName = 作品文件夹.split("\\")[-1].split('/')[-1]
        fileName = 作品文件夹+'/0_'+projectName+".json"
        f = open(fileName, 'w', encoding="utf-8")
        text = json.dumps(章节索引, sort_keys=True,
                          indent=4, ensure_ascii=False)
        f.write(text)
        f.close()
    else:
        print("无此文件夹")


def CreateHtml(dir1):
    '''
    创建html模板文件
    '''
    f1 = open('./manhua_0_index.html', 'r', encoding="utf-8")
    htmlMoBan = f1.read()
    f1.close()

    fileName = dir1+'/'+'0_index.html'
    f2 = open(fileName, 'w', encoding="utf-8")
    f2.write(htmlMoBan)
    f2.close()


def manhua_download_of_thread(name: str):
    JSON_FILE_NAME = name
    DIE_NAME = '../static/man_hua/'+os.path.splitext(name)[0].split('/')[-1]
    DownloadOfThread(JSON_FILE_NAME, DIE_NAME).Start()
    CreateIndexJson(DIE_NAME)
    CreateHtml(DIE_NAME)


if __name__ == "__main__":
    from manhua_works_index import create_manhua_works_index
    NAME = "地狱乐园"
    JSON_FILE_NAME = '../static/spiderData/man_hua/'+NAME+'.json'
    DIE_NAME = '../static/man_hua/'+NAME
    DownloadOfThread(JSON_FILE_NAME, DIE_NAME).Start()
    CreateIndexJson(DIE_NAME)
    CreateHtml(DIE_NAME)
    create_manhua_works_index()
    'python manhua_download_of_thread.py'
